Dijkstra's Algorithm/Dijkstramod.bas

Attribute VB_Name = "Dijkstramod"
Option Explicit
'(c)2002 by Louis. Algorithm by Dijkstra.
'
'NOTE: the code of this module was created out of VC sample code
'found on the Internet. This code works, but is not so fast.
'NOTE: this module and the related class module can be used
'as a General Function, you can add it to any kind of target project.
'
'Dijkstra Constants
Public Const DIJKSTRA_NO_CONNECTION = 256& ^ 3&
'DijkstraNodeStruct
Private Type DijkstraNodeStruct
    NodeDistance As Long
    NodePreviousIndex As Long
End Type
'other
Dim DijkstraclsNumber As Long
Dim DijkstraclsMain As Dijkstracls
Dim MsgString As String

Public Sub Dijkstra_FindPath(ByVal NodeNumber As LongByRef NodeLinkMatrix() As LongByVal NodeStartIndex As LongByVal NodeEndIndex As LongByRef PathLengthMin As LongByRef PathIndexNumber As LongByRef PathIndexArray() As Long)
    'on error resume next
    ReDim DijkstraNodeStructArray(1 To NodeNumber) As DijkstraNodeStruct
    Dim NodeIndex As Long
    Dim NodeDistance As Long
    Dim NodePreviousIndex As Long
    Dim NodeCostCurrent As Long
    Dim Temp As Long
    Dim Temp2 As Long
    Dim Tempstr$
    'preset
    '
    'DEBUG
    'For Temp = 1 To NodeNumber
    '    For Temp2 = 1 To NodeNumber
    '        Tempstr$ = CStr(NodeLinkMatrix(Temp, Temp2))
    '        Debug.Print Tempstr$ + String$(16 ‑ Len(Tempstr$), " ");
    '    Next Temp2
    '    Debug.Print
    'Next Temp

    'END OF DEBUG
    '
    Set DijkstraclsMain = Nothing
    '
    For Temp = 1 To NodeNumber
        DijkstraNodeStructArray(Temp).NodeDistance = DIJKSTRA_NO_CONNECTION 'preset
        DijkstraNodeStructArray(Temp).NodePreviousIndex = DIJKSTRA_NO_CONNECTION 'preset
    Next Temp
    '
    DijkstraNodeStructArray(NodeStartIndex).NodeDistance = 0 'preset
    DijkstraNodeStructArray(NodeStartIndex).NodePreviousIndex = DIJKSTRA_NO_CONNECTION 'preset
    '
    'begin
    '
    'Set DijkstraclsMain = New Dijkstracls 'no! must be Nothing (see Dijkstra_Enqueue())
    '
    Call Dijkstra_Enqueue(NodeStartIndex, 0, DIJKSTRA_NO_CONNECTION)
    '
    While (DijkstraclsNumber > 0)
        '
        Call Dijkstra_Dequeue(NodeIndex, NodeDistance, NodePreviousIndex)
        '
        For Temp = 1 To NodeNumber
            '
            NodeCostCurrent = NodeLinkMatrix(NodeIndex, Temp)
            If Not (NodeCostCurrent = DIJKSTRA_NO_CONNECTION) Then
                If ((DijkstraNodeStructArray(Temp).NodeDistance = DIJKSTRA_NO_CONNECTION) Or (DijkstraNodeStructArray(Temp).NodeDistance > (NodeCostCurrent + NodeDistance))) Then
                    DijkstraNodeStructArray(Temp).NodeDistance = NodeDistance + NodeCostCurrent
                    DijkstraNodeStructArray(Temp).NodePreviousIndex = NodeIndex
                    Call Dijkstra_Enqueue(Temp, NodeDistance + NodeCostCurrent, NodeIndex)
                End If
            End If
        Next Temp
    Wend
    'DEBUG
    'MsgString = "" 'reset
    'Call Dijkstra_PrintPath(DijkstraNodeStructArray(), NodeEndIndex)
    'MsgBox MsgString
    'END OF DEBUG
    PathIndexNumber = PathIndexNumber + 1
    If ((PathIndexNumber ‑ 1) Mod 64) = 0 Then
        ReDim Preserve PathIndexArray(1 To PathIndexNumber + 63) As Long
    End If
    PathIndexArray(PathIndexNumber) = NodeEndIndex
    Do
        If DijkstraNodeStructArray(PathIndexArray(PathIndexNumber)).NodePreviousIndex = DIJKSTRA_NO_CONNECTION Then Exit Do
        PathIndexNumber = PathIndexNumber + 1
        If ((PathIndexNumber ‑ 1) Mod 64) = 0 Then
            ReDim Preserve PathIndexArray(1 To PathIndexNumber + 63) As Long
        End If
        PathIndexArray(PathIndexNumber) = DijkstraNodeStructArray(PathIndexArray(PathIndexNumber ‑ 1)).NodePreviousIndex
    Loop
    'swap array (we couldn't assign in right order as only NodePreviousIndex items are known, not next)
    For Temp = 1 To Int(PathIndexNumber / 2)
        Temp2 = PathIndexArray(Temp)
        PathIndexArray(Temp) = PathIndexArray(PathIndexNumber ‑ Temp + 1)
        PathIndexArray(PathIndexNumber ‑ Temp + 1) = Temp2
    Next Temp
    PathLengthMin = DijkstraNodeStructArray(NodeEndIndex).NodeDistance
End Sub

Private Sub Dijkstra_Enqueue(ByVal NodeIndex As LongByVal NodeDistance As LongByVal NodePreviousIndex As Long)
    'on error resume next
    Dim DijkstraclsNew As New Dijkstracls
    Dim DijkstraclsLast As Dijkstracls
    'preset
    Set DijkstraclsLast = DijkstraclsMain 'IMPORTANT: use DijkstraclsLast, not DijkstraclsMain (for what reason ever, copied from sample, important)
    DijkstraclsNew.NodeIndex = NodeIndex
    DijkstraclsNew.NodeDistance = NodeDistance
    DijkstraclsNew.NodePreviousIndex = NodePreviousIndex
    Set DijkstraclsNew.DijkstraclsNext = Nothing
    'begin
    If (DijkstraclsMain Is Nothing) Then
        Set DijkstraclsMain = DijkstraclsNew
    Else
        While (Not (DijkstraclsLast.DijkstraclsNext Is Nothing))
            Set DijkstraclsLast = DijkstraclsLast.DijkstraclsNext
        Wend
        Set DijkstraclsLast.DijkstraclsNext = DijkstraclsNew
    End If
    DijkstraclsNumber = DijkstraclsNumber + 1&
End Sub

Private Sub Dijkstra_Dequeue(ByRef NodeIndex As LongByRef NodeDistance As LongByRef NodePreviousIndex As Long)
    'on error resume next
    If Not (DijkstraclsMain Is Nothing) Then
        NodeIndex = DijkstraclsMain.NodeIndex
        NodeDistance = DijkstraclsMain.NodeDistance
        NodePreviousIndex = DijkstraclsMain.NodePreviousIndex
        Set DijkstraclsMain = DijkstraclsMain.DijkstraclsNext
    End If
    DijkstraclsNumber = DijkstraclsNumber ‑ 1&
End Sub

Private Sub Dijkstra_PrintPath(ByRef DijkstraNodeStructArray() As DijkstraNodeStruct, ByVal NodeIndex As Long)
    'on error resume next 'this sub is used for debugging only
    If Not (DijkstraNodeStructArray(NodeIndex).NodePreviousIndex = DIJKSTRA_NO_CONNECTION) Then
        Call Dijkstra_PrintPath(DijkstraNodeStructArray(), DijkstraNodeStructArray(NodeIndex).NodePreviousIndex)
    End If
    'MsgString = MsgString + " " + DijkstraNodeStructArray(NodeIndex).NodeName
End Sub


[END OF FILE]